home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 010 / pasgames.arc / PLIFE.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1985-01-20  |  8.3 KB  |  314 lines

  1. program life;
  2.  
  3. const
  4.    height      = 24;   (* number of lines on screen *)
  5.    width       = 80;   (* number of columns on screen *)
  6.    minbound    = -1;   (* minimum dimension of screen bounds *)
  7.    clearscreen = 26;   (* screen clear character *)
  8.  
  9. type
  10.    state = (alive, dead);
  11.    cell = record
  12.              lookslikeitis : state;
  13.              nearby : integer;
  14.           end;
  15.    edges = record
  16.               left,
  17.               right,
  18.               top,
  19.               bottom : integer;
  20.            end;
  21.  
  22. var
  23.    board : array [minbound .. height] of array [minbound .. width] of cell;
  24.    population : integer;
  25.    births     : integer;
  26.    deaths     : integer;
  27.    ch         : char;
  28.    edge       : edges;
  29.  
  30. (*
  31.  * initializes the edges of the pattern. this starts representing a pattern
  32.  * which has no insides; the top is lower than the bottom, the left side is
  33.  * to the right of the right side. this ensures that the coordinates of the
  34.  * corner of the pattern after it is entered will be correct without needing
  35.  * to scan the entire array after the pattern is entered (a time consuming
  36.  * process).
  37.  *)
  38.  
  39. procedure resetedges;
  40.  
  41. begin
  42.    edge.top    := height - 1;
  43.    edge.right  := minbound + 1;
  44.    edge.left   := width - 1;
  45.    edge.bottom := minbound + 1;
  46. end;
  47.  
  48. procedure instructions;
  49.  
  50. var
  51.    answer : char;
  52.  
  53. begin
  54.    writeln('Would you like instructions for LIFE? ');
  55.    readln(answer);
  56.    while not (answer in ['y', 'n', 'Y', 'N']) do
  57.       begin
  58.       writeln('please answer yes or no');
  59.       readln(answer);
  60.       end;
  61.    if (answer = 'y') or (answer = 'Y') then
  62.       begin
  63.       writeln('LIFE simulates the growth of a colony of animals on a 0..',
  64.                height-1:1,' by 0..',width-1:1,' ''world''.');
  65.       writeln('Whether a cell is born, lives, or dies depends on the number');
  66.       writeln('of living animals immediately adjacent to it. If a cell is');
  67.       writeln('empty and has exactly 3 neighbors it will be born in the next');
  68.       writeln('generation. If it is alive and has either two or three');
  69.       writeln('neighbors, it will continue to live. Otherwise it dies of');
  70.       writeln('loneliness or overcrowding.');
  71.       writeln('   The initial pattern is entered by typing the row and then');
  72.       writeln('the column of the desired position. A cell is removed by entering');
  73.       writeln('its position again. To finish entering give a position outside');
  74.       writeln('of the dimensions of the screen. To stop a pattern, just hit');
  75.       writeln('any key. Type return to start.');
  76.       writeln;
  77.       readln(answer);
  78.       end;
  79.       write(chr(clearscreen));
  80. end;
  81.  
  82. (*
  83.  * initialize
  84.  * resets the board to empty (all dead and with no neighbors)
  85.  *)
  86.  
  87. procedure initialize;
  88.  
  89. var
  90.    down, across : integer;
  91.  
  92. begin
  93.    instructions;
  94.    for down := minbound to height do
  95.       for across := minbound to width do
  96.          begin
  97.          board[down, across].lookslikeitis := dead;
  98.          board[down, across].nearby := 0;
  99.          end;
  100.    resetedges;
  101. end;
  102.  
  103. (*
  104.  * max ( & min)
  105.  * returns the larger (smaller) of the two integer arguments
  106.  *)
  107.  
  108. function max(a, b: integer): integer;
  109.  
  110. begin
  111.    if a >= b then
  112.       max := a
  113.    else
  114.       max := b
  115. end;
  116.  
  117. function min(a, b: integer): integer;
  118.  
  119. begin
  120.    if a <= b then
  121.       min := a
  122.    else
  123.       min := b
  124. end;
  125.  
  126. (*
  127.  * determine if and how the co-ordinates passed as argument change the bounds
  128.  * of the pattern (the position of a box that could contain living cells),
  129.  * checking that it does not go off one of the sides of the board.
  130.  *)
  131.  
  132. procedure limits(x, y: integer);
  133.  
  134. begin
  135.    with edge do
  136.       begin
  137.       left   := min(left,x);
  138.       right  := max(right,x);
  139.       top    := min(top,y);
  140.       bottom := max(bottom,y);
  141.       end;
  142. end;
  143.  
  144. (*
  145.  * this erases the record of the neighbors of all the cells, in preparation
  146.  * for the new calculation of the nearby field
  147.  *)
  148.  
  149. procedure clearnearby;
  150.  
  151. var
  152.    down, across : integer;
  153.  
  154. begin
  155.    for down := edge.top - 1 to edge.bottom + 1 do
  156.       for across := edge.left - 1 to edge.right + 1 do
  157.          board[down,across].nearby := 0;
  158. end;
  159.  
  160. (*
  161.  * computes the number of adjacent cells, and thus which cells will survive
  162.  * through the next generation. To speed this up, the middle cell of the 3 by 3
  163.  * matrix which is being examioned is included in the count, even though it is
  164.  * not really a neighbor of itself. this off-by-one discrepancy is taken into
  165.  * account in the board update.
  166.  *)
  167.  
  168. procedure countneighbors;
  169.  
  170. var
  171.    down, across : integer;
  172.    deltadown, deltaacross : integer;
  173.  
  174. begin
  175.    clearnearby;
  176.    for down := edge.top - 1 to edge.bottom + 1 do
  177.       for across := edge.left - 1 to edge.right + 1 do
  178.          if board[down,across].lookslikeitis = alive then
  179.             for deltadown := -1 to 1 do
  180.                for deltaacross := -1 to 1 do
  181.                   board[down+deltadown,across+deltaacross].nearby :=
  182.                   board[down+deltadown,across+deltaacross].nearby + 1;
  183. end;
  184.  
  185. (*
  186.  * update
  187.  * if a birth or death occurs, the screen is updated.
  188.  *)
  189.  
  190. procedure update;
  191.  
  192. var
  193.    down, across : integer;
  194.    localedge : edges;
  195.  
  196. begin
  197.    births := 0;
  198.    deaths := 0;
  199.    localedge := edge;
  200.    resetedges;
  201.    for down := max(minbound+1, localedge.top-1) to
  202.                min(height-1, localedge.bottom+1) do
  203.       for across := max(minbound+1, localedge.left-1) to
  204.                     min(width-1,localedge.right+1) do
  205.          with board[down][across] do
  206.             case lookslikeitis of
  207.                dead:
  208.                    if nearby = 3 then
  209.                       begin
  210.                       lookslikeitis := alive;
  211.                       gotoxy(across,down);
  212.                       write('*');
  213.                       limits(across,down);
  214.                       births := births + 1;
  215.                       end;
  216.                 alive:
  217.                    if (nearby = 3) or (nearby = 4) then
  218.                       limits(across,down)
  219.                    else
  220.                       begin
  221.                       lookslikeitis := dead;
  222.                       gotoxy(across,down);
  223.                       write(' ');
  224.                       deaths := deaths + 1;
  225.                       end;
  226.                 end;
  227.    population := population + births - deaths;
  228. end;
  229.  
  230. (*
  231.  * get the starting positions of the cells
  232.  *)
  233.  
  234. procedure getpositions;
  235.  
  236. var
  237.    down, across : integer;
  238.    finished : boolean;
  239.  
  240. (*
  241.  * this is needed to reprint the top line of the pattern, which is destroyed
  242.  * by the prompt line which asks for the cell positions.
  243.  *)
  244.  
  245. procedure reprinttopline;
  246.  
  247. var
  248.    across : integer;
  249.  
  250. begin
  251.    gotoxy(1,1);
  252.    for across := minbound + 1 to width - 1 do
  253.       if board[minbound + 1][across].lookslikeitis = dead then
  254.          write(' ')
  255.       else
  256.          write('*');
  257. end;
  258.  
  259. begin
  260.    finished := false;
  261.    population := 0;
  262.    gotoxy(1,1);
  263.    write('Position of cell #',population + 1:1,' is : ');
  264.    while not finished do
  265.       begin
  266.       readln(down, across);
  267.       if (down <= minbound) or
  268.          (down >= height) or
  269.          (across <= minbound) or
  270.          (across >= width) then
  271.          finished := true
  272.       else
  273.          with board[down][across] do
  274.             begin
  275.             limits(across, down);
  276.             gotoxy(across, down);
  277.             if lookslikeitis = alive then
  278.                begin
  279.                   write(' ');
  280.                   lookslikeitis := dead;
  281.                   population := population - 1;
  282.                   end
  283.             else
  284.                begin
  285.                write('*');
  286.                lookslikeitis := alive;
  287.                population := population + 1;
  288.                end;
  289.             gotoxy(1,1);
  290.             write('Position of cell #',population + 1:1,' is : ');
  291.             end;
  292.       end;
  293.       reprinttopline;
  294. end;
  295.  
  296. begin
  297.    initialize;
  298.    getpositions;
  299.    repeat
  300.       countneighbors;
  301.       update;
  302.    until (population = 0) or ((births = 0) and (deaths = 0)) or keypressed;
  303.    gotoxy(1,1);
  304.    if keypressed then
  305.       readln(ch)
  306.    else
  307.       if population = 0 then
  308.          writeln('This colony has died.')
  309.       else
  310.          writeln('The pattern is stable.');
  311. end.
  312.  
  313.  
  314.